Adding a Deck Object to My C# Five-Card Poker Hand Program

Every few years, I take another look at creating a library of functions for a five-card poker hand. I recently created C# code for a Card class and a Hand class, and functions to classify a Hand (“ThreeKind”, “TwoPair”, etc.) and compare two hands (“3c 3d Th Ts Jd” is less than “2h 2s Qh Qs Kd”, etc.)

On a recent weekend morning, I decided to implement a SingleDeck class. After a couple of hours of coding, I had a demo up and running. The interface looks like:

SingleDeck deck = new SingleDeck(seed: 1);

for (int i = 0; i "lt" 3; ++i) // "less-than"
{
  deck.Shuffle();
  Hand h1 = deck.DealHand();
  Hand h2 = deck.DealHand();
  Console.WriteLine("h1: " + h1 + " " +
    h1.HandType());
  Console.WriteLine("h2: " + h2 + " " +
    h2.HandType());
  int cmp = Hand.Compare(h1, h2);
  if (cmp == -1)
    Console.WriteLine("h1 less-than h2");
  else if (cmp == +1)
    Console.WriteLine("h1 greater-than h2");
  else if (cmp == 0)
    Console.WriteLine("h1 equal h2");
}

The output looks something like:

h1: 2c-3c-8c-Jc-Ah HighCard
h2: 2d-4d-7c-Td-Ks HighCard
h1 greater-than h2

h1: 3d-4h-7c-8h-Kh HighCard
h2: 4c-6c-Tc-Qc-Qs OnePair
h1 less-than h2

h1: 3d-7d-8d-Jd-Qd Flush
h2: 7s-8h-Tc-Td-Ts ThreeKind
h1 greater-than h2

The seed value for the SingleDeck constructor is for a internal random number generator that is used by the Shuffle() method. The DealHand() method deals out a Hand object of five cards. The deck is shuffled before each pair of hands is dealt.

There are endless design options. In some of the groups I worked for, designing classes for a poker hand was a common interview question because there’s no correct design — but countless designs with pros and cons related to clarity, efficiency, performance, maintainability, testability, and extendibility.

Interestingly, in all the years I saw poker used as the basis for an interview question, not a single guy was unfamiliar with poker, however, the vast majority of women candidates were not entirely familiar with poker. (Admittedly, the number of women candidates we saw for actual engineering positions was tiny — the huge majority of women interviewed for pseudo-technical positions such as program management and so interviewers had to use entirely different questions.)

When I get a chance, I might adapt my demo code to deal with seven-card hands. The idea is to deal out seven cards, then examine all 21 subsets (Choose(7,5) = Choose(7,2) = (7 * 6) / (2 * 1) = 21) that have five cards, and return the five-card set that is best. But that’s for another day.



Coin operated games related to poker have been around for well over 100 years. Here are three beautiful examples. Left: The “Play-Boy” pinball machine by Gottlieb, circa 1932. Center: The “Little Perfection” trade stimulator by Mills Novelty, circa 1903. Right: The “Play Poker” game. This is a very rare game and I could find very little information about it. I think it may be from Peo Manufacturing, circa 1930.


Demo code. Replace “lt” (less-than), “gt”, “lte”, “gte”, “and” with Boolean operator symbols — my lame blog editor sometimes chokes on symbols.

using System;
using System.IO;
using System.Collections.Generic;

namespace Poker
{
  internal class PokerProgram
  {
    static void Main(string[] args)
    {
      Console.WriteLine("\nBegin five-card poker with C# ");

      Card c1 = new Card(14, 3);  // As
      Console.Write("\nCard c1 = ");
      Console.WriteLine(c1.ToString());

      Card c2 = new Card("Td");
      Console.Write("Card c2 = ");
      Console.WriteLine(c2);

      Hand h1 = new Hand("7cTsJc8d9h"); 
      Console.WriteLine("\nHand h1: ");
      Console.WriteLine(h1);
      Console.Write(h1.GetHandTypeStr() + " (");  // Straight
      Console.WriteLine(h1.GetHandTypeInt() + ")");  // 4

      Hand h2 = new Hand(new Card("6s"), new Card("Ah"),
        new Card("6h"), new Card("Ac"), new Card("6d"));
      Console.WriteLine("\nHand h2: ");
      Console.WriteLine(h2);
      Console.Write(h2.GetHandTypeStr() + " (");  // FullHouse
      Console.WriteLine(h2.GetHandTypeInt() + ")");  // 6

      List"lt"Card"gt" lst = new List"lt"Card"gt"();
      lst.Add(new Card("5c")); lst.Add(new Card("5d"));
      lst.Add(new Card("9c")); lst.Add(new Card("9d"));
      lst.Add(new Card("Qh"));
      Hand h3 = new Hand(lst);
      Console.WriteLine("\nHand h3: ");
      Console.WriteLine(h3);
      Console.Write(h3.GetHandTypeStr() + " (");  // TwoPair
      Console.WriteLine(h3.GetHandTypeInt() + ")");  // 2

      int cmp1 = Hand.Compare(h1, h2);
      Console.Write("\nHand.Compare(h1, h2) = ");
      Console.WriteLine(cmp1);

      int cmp2 = Hand.Compare(h2, h3);
      Console.Write("\nHand.Compare(h2, h3) = ");
      Console.WriteLine(cmp2);

      Console.WriteLine("\nCreating and shuffling deck ");
      SingleDeck d1 = new SingleDeck(seed: 0);
      d1.Shuffle();
      d1.Show();

      Hand h4 = d1.DealHand();
      Console.WriteLine("\nDealing Hand from deck: ");
      Console.WriteLine(h4);

      Console.WriteLine("\nRemoving 43 cards from deck");
      List"lt"Card"gt" listCards = d1.DealListCards(43);
      Console.WriteLine("Deck is now: ");
      d1.Show();

      Console.WriteLine("\nEnd demo ");
      Console.ReadLine();

      //Console.WriteLine("\nBegin antique poker machine" +
      //  " simulation ");

      //string[] handTypes = new string[] { "HighCard",
      //  "OnePair", "TwoPair" , "ThreeKind" , "Straight",
      //  "Flush" , "FullHouse",  "FourKind",
      //  "StraightFlush", "RoyalFlush" };

      //double[] trueProbs = new double[] { 0.50117700,
      //  0.42256900, 0.04753900, 0.02112800, 0.00392500,
      //  0.00196500, 0.00144100, 0.00024010, 0.00001390,
      //  0.00000154};

      //int nTrials = 10_000_000;
      //Console.WriteLine("\nPlaying machine " +
      //  nTrials + " times");
      //double[] probs = MachineProbs(nTrials, 0);
      //Console.WriteLine("");

      //Console.WriteLine("          " +
      //  "      machine     standard deck");
      //for (int i = 0; i "lt" 10; ++i)
      //{
      //  Console.Write(handTypes[i].ToString().
      //    PadRight(14) + "  ");
      //  Console.Write(probs[i].ToString("F8") + "  ");
      //  Console.WriteLine(trueProbs[i].ToString("F8"));
      //}

      //Console.WriteLine("\nEnd poker machine simulation ");
      //Console.ReadLine();

    } // Main

    // ------------------------------------------------------

    static double[] MachineProbs(int nTrials, int seed)
    {
      Random rnd = new Random(seed);
      string[] reels = new string[5];
      // Charles Fey and Co.
      reels[0] = "2d 3c 4s 6h 7d 8c 9s Qd Kc As";
      reels[1] = "2h 3d 4c 5h 7h 8d 9c Qh Kd Ac";
      reels[2] = "3h 4d 5d 6s 8h 9d Tc Js Kh Ad";
      reels[3] = "2s 4h 5c 6c 7s 9h Td Jc Qs Ah";
      reels[4] = "2c 3s 5s 6d 7c 8s Th Jd Qc Ks";
      // out:  Ts, Jh

      Console.WriteLine("\nMachine reels: ");
      for (int i = 0; i "lt" 5; ++i)
        Console.WriteLine(reels[i]);

      int[] counts = new int[10];
      double[] probs = new double[10];

      for (int t = 0; t "lt" nTrials; ++t)
      {
        string hs = "";
        for (int i = 0; i "lt" 5; ++i) // each reel
        {
          int j = rnd.Next(0, 10); // 0 to 9 inclusive
          int idx = 3 * j;  // 0 to 27: 0, 3, 6 . .
          string cs = reels[i].Substring(idx, 2);
          hs = hs + cs;  // like "Kc9h2d5dJs"
        }

        Hand h = new Hand(hs);  // List of 5 cards
        int hIdx = h.GetHandTypeInt();  // 0 (HighCard) to 9
        ++counts[hIdx];
      }

      for (int i = 0; i "lt" 10; ++i)
        probs[i] = (1.0 * counts[i]) / nTrials;

      return probs;
    }

    // ------------------------------------------------------

  } // Program

  // --------------------------------------------------------

  public class Card : IComparable"lt"Card"gt"
  {
    // 0,1 not used. 11=J, 12=Q, 13=K, 14=A
    public int rank;
    // 0=clubs, 1=diamonds, 2=hearts, 3=spades
    public int suit;

    public Card(int rank, int suit)
    {
      this.rank = rank; this.suit = suit;
    }

    public Card(string c)
    {
      char rnk = c[0]; char sut = c[1];
      if (rnk == 'T') this.rank = 10;
      else if (rnk == 'J') this.rank = 11;
      else if (rnk == 'Q') this.rank = 12;
      else if (rnk == 'K') this.rank = 13;
      else if (rnk == 'A') this.rank = 14;
      else this.rank = int.Parse(rnk.ToString());

      if (sut == 'c') this.suit = 0;
      else if (sut == 'd') this.suit = 1;
      else if (sut == 'h') this.suit = 2;
      else if (sut == 's') this.suit = 3;
    }

    public override string ToString()
    {
      string rnk = ""; string sut = "";
      if (this.rank == 10) rnk = "T";
      else if (this.rank == 11) rnk = "J";
      else if (this.rank == 12) rnk = "Q";
      else if (this.rank == 13) rnk = "K";
      else if (this.rank == 14) rnk = "A";
      else rnk = this.rank.ToString();

      if (this.suit == 0) sut = "c";
      else if (this.suit == 1) sut = "d";
      else if (this.suit == 2) sut = "h";
      else if (this.suit == 3) sut = "s";

      return rnk + sut;
    }

    public int CompareTo(Card other)
    {
      // sort cards in a hand from low (Two) to high (Ace)
      if (this.rank.CompareTo(other.rank) == 0)
      {
        return this.suit.CompareTo(other.suit);
      }
      return this.rank.CompareTo(other.rank);
    }

  } // class Card

  // --------------------------------------------------------

  public class Hand
  {
    // 5-card poker hand
    // Hand types: "RoyalFlush", "StraightFlush",
    // "FourKind", "FullHouse", "Flush" , "Straight",
    // "ThreeKind", "TwoPair", "OnePair", "HighCard"

    public List"lt"Card"gt" cards;

    public Hand(List"lt"Card"gt" lst)
    {
      this.cards = new List"lt"Card"gt"();
      for (int i = 0; i "lt" 5; ++i)
        this.cards.Add(lst[i]);
      this.cards.Sort();
    }

    public Hand(Card c1, Card c2, Card c3,
      Card c4, Card c5)
    {
      this.cards = new List"lt"Card"gt"();
      this.cards.Add(c1); this.cards.Add(c2);
      this.cards.Add(c3); this.cards.Add(c4);
      this.cards.Add(c5);
      this.cards.Sort();
    }

    public Hand(string s) // s like "Js3h7d7cAd"
    {
      this.cards = new List"lt"Card"gt"();
      this.cards.Add(new Card(s.Substring(0, 2)));
      this.cards.Add(new Card(s.Substring(2, 2)));
      this.cards.Add(new Card(s.Substring(4, 2)));
      this.cards.Add(new Card(s.Substring(6, 2)));
      this.cards.Add(new Card(s.Substring(8, 2)));
      this.cards.Sort();
    }

    public override string ToString()
    {
      string h = "";
      for (int i = 0; i "lt" 4; ++i)
        h += this.cards[i].ToString() + "-";
      h += this.cards[4];
      return h;
    }

    public string ToTerseString()
    {
      string h = "";
      for (int i = 0; i "lt" 4; ++i)
        h += this.cards[i].ToString();
      h += this.cards[4];
      return h;
    }

    // ------------------------------------------------------

    // Hand Type methods:
    // GetHandTypeStr(), GetHandTypeInt(),
    //
    // IsRoyalFlush(), IsStraightFlush(), 
    // IsFourKind(), IsFullHouse(), IsFlush(),
    // IsStraight(), IsThreeKind(), IsTwoPair(),
    // IsOnePair(), IsHighCard()
    //
    // helpers: HasFlush(), HasStraight(),


    // ------------------------------------------------------

    public string GetHandTypeStr()
    {
      if (IsRoyalFlush(this) == true)
        return "RoyalFlush";
      else if (IsStraightFlush(this) == true)
        return "StraightFlush";
      else if (IsFourKind(this) == true)
        return "FourKind";
      else if (IsFullHouse(this) == true)
        return "FullHouse";
      else if (IsFlush(this) == true)
        return "Flush";
      else if (IsStraight(this) == true)
        return "Straight";
      else if (IsThreeKind(this) == true)
        return "ThreeKind";
      else if (IsTwoPair(this) == true)
        return "TwoPair";
      else if (IsOnePair(this) == true)
        return "OnePair";
      else if (IsHighCard(this) == true)
        return "HighCard";
      else
        return "Unknown";
    }

    // ------------------------------------------------------

    public int GetHandTypeInt()
    {
      if (IsRoyalFlush(this) == true)
        return 9;
      else if (IsStraightFlush(this) == true)
        return 8;
      else if (IsFourKind(this) == true)
        return 7;
      else if (IsFullHouse(this) == true)
        return 6;
      else if (IsFlush(this) == true)
        return 5;
      else if (IsStraight(this) == true)
        return 4;
      else if (IsThreeKind(this) == true)
        return 3;
      else if (IsTwoPair(this) == true)
        return 2;
      else if (IsOnePair(this) == true)
        return 1;
      else if (IsHighCard(this) == true)
        return 0;
      else
        return -1;
    }

    // ------------------------------------------------------

    private static bool HasFlush(Hand h)
    {
      if ((h.cards[0].suit == h.cards[1].suit) "and"
          (h.cards[1].suit == h.cards[2].suit) "and"
          (h.cards[2].suit == h.cards[3].suit) "and"
          (h.cards[3].suit == h.cards[4].suit))
        return true;

      return false;
    }

    // ------------------------------------------------------

    private static bool HasStraight(Hand h)
    {
      // check special case of Ace-low straight
      // 2, 3, 4, 5, A when sorted
      if (h.cards[0].rank == 2 "and"
        h.cards[1].rank == 3 "and"
        h.cards[2].rank == 4 "and"
        h.cards[3].rank == 5 "and"
        h.cards[4].rank == 14)
        return true;

      // otherwise, check for 5 consecutive
      if ((h.cards[0].rank == h.cards[1].rank - 1) "and"
        (h.cards[1].rank == h.cards[2].rank - 1) "and"
        (h.cards[2].rank == h.cards[3].rank - 1) "and"
        (h.cards[3].rank == h.cards[4].rank - 1))
        return true;

      return false;
    }

    // ------------------------------------------------------

    private static bool IsRoyalFlush(Hand h)
    {
      if (HasStraight(h) == true "and" HasFlush(h) == true
        "and" h.cards[0].rank == 10)
        return true;
      else
        return false;
    }

    // ------------------------------------------------------

    private static bool IsStraightFlush(Hand h)
    {
      if (HasStraight(h) == true "and" HasFlush(h) == true
        "and" h.cards[0].rank != 10)
        return true;
      else
        return false;
    }

    // ------------------------------------------------------

    private static bool IsFourKind(Hand h)
    {
      // AAAA B or B AAAA if sorted
      if ((h.cards[0].rank == h.cards[1].rank) "and"
        (h.cards[1].rank == h.cards[2].rank) "and"
        (h.cards[2].rank == h.cards[3].rank) "and"
        (h.cards[3].rank != h.cards[4].rank))
        return true;

      if ((h.cards[1].rank == h.cards[2].rank) "and"
        (h.cards[2].rank == h.cards[3].rank) "and"
        (h.cards[3].rank == h.cards[4].rank) "and"
        (h.cards[0].rank != h.cards[1].rank))
        return true;

      return false;
    }

    // ------------------------------------------------------

    private static bool IsFullHouse(Hand h)
    {
      // AAA BB or BB AAA if sorted
      if ((h.cards[0].rank == h.cards[1].rank) "and"
        (h.cards[1].rank == h.cards[2].rank) "and"
        (h.cards[3].rank == h.cards[4].rank) "and"
        (h.cards[2].rank != h.cards[3].rank))
        return true;

      // BB AAA
      if ((h.cards[0].rank == h.cards[1].rank) "and"
        (h.cards[2].rank == h.cards[3].rank) "and"
        (h.cards[3].rank == h.cards[4].rank) "and"
        (h.cards[1].rank != h.cards[2].rank))
        return true;

      return false;
    }

    // ------------------------------------------------------

    private static bool IsFlush(Hand h)
    {
      if (HasFlush(h) == true "and"
        HasStraight(h) == false)
        return true; // no StraightFlush or RoyalFlush
      else
        return false;
    }

    // ------------------------------------------------------

    private static bool IsStraight(Hand h)
    {
      if (HasStraight(h) == true "and"
        HasFlush(h) == false) // no SF or RF
        return true;
      else
        return false;
    }

    // ------------------------------------------------------

    private static bool IsThreeKind(Hand h)
    {
      // assumes not 4K or FH
      // AAA B C or B AAA C or B C AAA if sorted
      if ((h.cards[0].rank == h.cards[1].rank) "and"
        (h.cards[1].rank == h.cards[2].rank) "and"
        (h.cards[2].rank != h.cards[3].rank) "and"
        (h.cards[3].rank != h.cards[4].rank))
        return true;

      if ((h.cards[1].rank == h.cards[2].rank) "and"
        (h.cards[2].rank == h.cards[3].rank) "and"
        (h.cards[0].rank != h.cards[1].rank) "and"
        (h.cards[3].rank != h.cards[4].rank))
        return true;

      if ((h.cards[2].rank == h.cards[3].rank) "and"
        (h.cards[3].rank == h.cards[4].rank) "and"
        (h.cards[0].rank != h.cards[1].rank) "and"
        (h.cards[1].rank != h.cards[2].rank))
        return true;

      return false;
    }

    // ------------------------------------------------------

    private static bool IsTwoPair(Hand h)
    {
      // AA BB C or AA C BB or C AA BB if sorted
      if ((h.cards[0].rank == h.cards[1].rank) "and"
        (h.cards[2].rank == h.cards[3].rank) "and"
        (h.cards[1].rank != h.cards[2].rank) "and"
        (h.cards[3].rank != h.cards[4].rank))
        return true;  // AA BB C

      if ((h.cards[0].rank == h.cards[1].rank) "and"
        (h.cards[3].rank == h.cards[4].rank) "and"
        (h.cards[1].rank != h.cards[2].rank) "and"
        (h.cards[2].rank != h.cards[3].rank))
        return true;  // AA C BB

      if ((h.cards[1].rank == h.cards[2].rank) "and"
        (h.cards[3].rank == h.cards[4].rank) "and"
        (h.cards[0].rank != h.cards[1].rank) "and"
        (h.cards[2].rank != h.cards[3].rank))
        return true;  // C AA BB

      return false;
    }

    // ------------------------------------------------------

    private static bool IsOnePair(Hand h)
    {
      // AA B C D or B AA C D or B C AA D or B C D AA
      if ((h.cards[0].rank == h.cards[1].rank) "and"
        (h.cards[1].rank != h.cards[2].rank) "and"
        (h.cards[2].rank != h.cards[3].rank) "and"
        (h.cards[3].rank != h.cards[4].rank))
        return true;  // AA B C D

      if ((h.cards[1].rank == h.cards[2].rank) "and"
        (h.cards[0].rank != h.cards[1].rank) "and"
        (h.cards[2].rank != h.cards[3].rank) "and"
        (h.cards[3].rank != h.cards[4].rank))
        return true;  // B AA C D

      if ((h.cards[2].rank == h.cards[3].rank) "and"
        (h.cards[0].rank != h.cards[1].rank) "and"
        (h.cards[1].rank != h.cards[2].rank) "and"
        (h.cards[3].rank != h.cards[4].rank))
        return true;  // B C AA D

      if ((h.cards[3].rank == h.cards[4].rank) "and"
        (h.cards[0].rank != h.cards[1].rank) "and"
        (h.cards[1].rank != h.cards[2].rank) "and"
        (h.cards[2].rank != h.cards[3].rank))
        return true;  // B C D AA

      return false;
    }

    // ------------------------------------------------------

    private static bool IsHighCard(Hand h)
    {
      if (HasFlush(h) == true)
        return false;
      else if (HasStraight(h) == true)
        return false;
      else
      {
        // all remaining have at least one pair
        if ((h.cards[0].rank == h.cards[1].rank) ||
            (h.cards[1].rank == h.cards[2].rank) ||
            (h.cards[2].rank == h.cards[3].rank) ||
            (h.cards[3].rank == h.cards[4].rank))
          return false;
      }

      return true;
    }

    // ------------------------------------------------------

    // Hand comparison methods
    // Hand.Compare() calls:
    // BreakTieStraightFlush(), BreakTieFourKind(),
    // BreakTieFullHouse(), BreakTieFlush(),
    // BreakTieStraight(), BreakTieThreeKind(),
    // BreakTieTwoPair(), BreakTieOnePair(),
    // BreakTieHighCard()

    // ------------------------------------------------------

    public static int Compare(Hand h1, Hand h2)
    {
      // -1 if h1 "lt" h2, +1 if h1 "gt" h2, 0 if h1 == h2

      int h1Idx = h1.GetHandTypeInt();  // like 6
      int h2Idx = h2.GetHandTypeInt();

      // different hand types - easy
      if (h1Idx "lt" h2Idx)
        return -1;
      else if (h1Idx "gt" h2Idx)
        return +1;
      else // same hand types so break tie
      {
        string h1HandType = h1.GetHandTypeStr();
        string h2HandType = h2.GetHandTypeStr();

        if (h1HandType != h2HandType)
          Console.WriteLine("Logic error ");

        if (h1HandType == "RoyalFlush")
          return 0; // two Royal Flush always tie
        else if (h1HandType == "StraightFlush")
          return BreakTieStraightFlush(h1, h2);
        else if (h1HandType == "FourKind")
          return BreakTieFourKind(h1, h2);
        else if (h1HandType == "FullHouse")
          return BreakTieFullHouse(h1, h2);
        else if (h1HandType == "Flush")
          return BreakTieFlush(h1, h2);
        else if (h1HandType == "Straight")
          return BreakTieStraight(h1, h2);
        else if (h1HandType == "ThreeKind")
          return BreakTieThreeKind(h1, h2);
        else if (h1HandType == "TwoPair")
          return BreakTieTwoPair(h1, h2);
        else if (h1HandType == "OnePair")
          return BreakTieOnePair(h1, h2);
        else if (h1HandType == "HighCard")
          return BreakTieHighCard(h1, h2);
      }
      return -2;  // error
    }

    // ------------------------------------------------------

    private static int BreakTieStraightFlush(Hand h1,
      Hand h2)
    {
      // check special case of Ace-low straight flush
      // check one or two Ace-low hands
      // h1 is Ace - low, h2 not Ace - low.h1 is less
      if ((h1.cards[0].rank == 2 "and"
        h1.cards[4].rank == 14) "and"  // because sorted!
        !(h2.cards[0].rank == 2 "and"
        h2.cards[4].rank == 14))
        return -1;

      //  h1 not Ace - low, h2 is Ace - low, h1 better
      else if (!(h1.cards[0].rank == 2 "and"
        h1.cards[4].rank == 14) "and"
        (h2.cards[0].rank == 2 "and"
        h2.cards[4].rank == 14))
        return +1;
      //  two Ace-low hands
      else if ((h1.cards[0].rank == 2 "and"
        h1.cards[4].rank == 14) "and"  // Ace-low
        (h2.cards[0].rank == 2 "and"
        h2.cards[4].rank == 14))  // Ace-low
        return 0;

      //  no Ace-low straight flush check high cards
      if (h1.cards[4].rank "lt" h2.cards[4].rank)
        return -1;
      else if (h1.cards[4].rank "gt" h2.cards[4].rank)
        return 1;
      else
        return 0;
    }

    private static int BreakTieFourKind(Hand h1,
      Hand h2)
    {
      // AAAA-B or B-AAAA
      // the off-card is at [0] or at [4]
      // find h1 four-card and off-card ranks
      int h1FourRank; int h1OffRank;
      if (h1.cards[0].rank == h1.cards[1].rank)
      {
        // 1st two cards same so off-rank at [4]
        h1FourRank = h1.cards[0].rank;
        h1OffRank = h1.cards[4].rank;
      }
      else
      {
        // 1st two cards diff so off-rank at [0]
        h1FourRank = h1.cards[4].rank;
        h1OffRank = h1.cards[0].rank;
      }

      int h2FourRank; int h2OffRank;
      if (h2.cards[0].rank == h2.cards[1].rank)
      {
        h2FourRank = h2.cards[0].rank;
        h2OffRank = h2.cards[4].rank;
      }
      else
      {
        h2FourRank = h2.cards[4].rank;
        h2OffRank = h2.cards[0].rank;
      }

      if (h1FourRank "lt" h2FourRank) // like 4K, 4A
        return -1;
      else if (h1FourRank "gt" h2FourRank)
        return +1;
      else // both hands same four-kind (mult. decks)
      {
        if (h1OffRank "lt" h2OffRank)
          return -1;  // like 3c 9c9d9h9s "lt" Qd 9c9d9h9s
        else if (h1OffRank "gt" h2OffRank)
          return +1;  // like Jc 4c4d4h4s "gt" 9s 4c4d4h4s
        else if (h1OffRank == h2OffRank)
          return 0;
      }
      throw new Exception("Fatal logic BreakTieFourKind");
    }

    private static int BreakTieFullHouse(Hand h1,
      Hand h2)
    {
      // determine high rank (3 kind) and low rank (2 kind)
      // JJJ 55 or 33 KKK
      // if [1] == [2] 3 kind at [0][1][2]
      // if [1] != [2] 3 kind at [2][3][4]
      int h1ThreeRank; int h1TwoRank;
      if (h1.cards[1].rank == h1.cards[2].rank)
      {
        // if [1] == [2] 3 kind at [0][1][2]
        h1ThreeRank = h1.cards[0].rank;
        h1TwoRank = h1.cards[4].rank;
      }
      else
      {
        // if [1] != [2] 3 kind at [2][3][4]
        h1ThreeRank = h1.cards[4].rank;
        h1TwoRank = h1.cards[0].rank;
      }

      int h2ThreeRank; int h2TwoRank;
      if (h2.cards[1].rank == h2.cards[2].rank)
      {
        // if [1] == [2] 3 kind at [0][1][2]
        h2ThreeRank = h2.cards[0].rank;
        h2TwoRank = h2.cards[4].rank;
      }
      else
      {
        // if [1] != [2] 3 kind at [2][3][4]
        h2ThreeRank = h2.cards[4].rank;
        h2TwoRank = h2.cards[0].rank;
      }

      if (h1ThreeRank "lt" h2ThreeRank)
        return -1;
      else if (h1ThreeRank "gt" h2ThreeRank)
        return +1;
      else // both hands same three-kind (mult. decks)
      {
        if (h1TwoRank "lt" h2TwoRank)
          return -1;  // like 3c3d 9c9d9h "lt" QdQs 9c9d9h
        else if (h1TwoRank "gt" h2TwoRank)
          return +1;  // like 3c3d 9c9d9h "gt" 2d2s 9c9d9h
        else if (h1TwoRank == h2TwoRank)
          return 0;
      }
      throw new Exception("Fatal logic BreakTieFullHouse");
    }

    private static int BreakTieFlush(Hand h1, Hand h2)
    {
      // compare rank of high cards
      if (h1.cards[4].rank "lt" h2.cards[4].rank)
        return -1;
      else if (h1.cards[4].rank "gt" h2.cards[4].rank)
        return +1;
      // high cards equal so check at [3]
      else if (h1.cards[3].rank "lt" h2.cards[3].rank)
        return -1;
      else if (h1.cards[3].rank "gt" h2.cards[3].rank)
        return +1;
      // and so on
      else if (h1.cards[2].rank "lt" h2.cards[2].rank)
        return -1;
      else if (h1.cards[2].rank "gt" h2.cards[2].rank)
        return +1;
      //
      else if (h1.cards[1].rank "lt" h2.cards[1].rank)
        return -1;
      else if (h1.cards[1].rank "gt" h2.cards[1].rank)
        return +1;
      //
      else if (h1.cards[0].rank "lt" h2.cards[0].rank)
        return -1;
      else if (h1.cards[0].rank "gt" h2.cards[0].rank)
        return +1;
      //
      else
        return 0; // all ranks the same!
    }

    private static int BreakTieStraight(Hand h1, Hand h2)
    {
      // both hands are straights but one could be Ace-low
      // check special case of one or two Ace-low hands
      // h1 is Ace-low, h2 not Ace-low. h1 is less
      if ((h1.cards[0].rank == 2 "and"  // Ace-low (sorted!)
        h1.cards[4].rank == 14) "and"
        !(h2.cards[0].rank == 2 "and"
        h2.cards[4].rank == 14))
        return -1;
      // h1 not Ace-low, h2 is Ace-low, h1 is better
      else if (!(h1.cards[0].rank == 2 "and"
        h1.cards[4].rank == 14) "and"
        (h2.cards[0].rank == 2 "and"
        h2.cards[4].rank == 14))
        return +1;
      // two Ace-low hands
      else if ((h1.cards[0].rank == 2 "and"
        h1.cards[4].rank == 14) "and"
        (h2.cards[0].rank == 2 "and"
        h2.cards[4].rank == 14))
        return 0;

      // no Ace-low hands so just check high card
      if (h1.cards[4].rank "lt" h2.cards[4].rank)
        return -1;
      else if (h1.cards[4].rank "gt" h2.cards[4].rank)
        return +1;
      else if (h1.cards[4].rank == h2.cards[4].rank)
        return 0;
      else
        throw new
          Exception("Fatal logic BreakTieStraight");
    }

    private static int BreakTieThreeKind(Hand h1, Hand h2)
    {
      // assumes multiple decks possible
      // (TTT L H) or (L TTT H) or (L H TTT)
      int h1ThreeRank = 0; int h1LowRank = 0;
      int h1HighRank = 0;
      if (h1.cards[0].rank == h1.cards[1].rank "and"
        h1.cards[1].rank == h1.cards[2].rank)
      {
        h1ThreeRank = h1.cards[0].rank;
        h1LowRank = h1.cards[3].rank;
        h1HighRank = h1.cards[4].rank;
      }
      else if (h1.cards[1].rank == h1.cards[2].rank "and"
        h1.cards[2].rank == h1.cards[3].rank)
      {
        h1LowRank = h1.cards[0].rank;
        h1ThreeRank = h1.cards[1].rank;
        h1HighRank = h1.cards[4].rank;
      }
      else if (h1.cards[2].rank == h1.cards[3].rank "and"
        h1.cards[3].rank == h1.cards[4].rank)
      {
        h1LowRank = h1.cards[0].rank;
        h1HighRank = h1.cards[1].rank;
        h1ThreeRank = h1.cards[4].rank;
      }

      int h2ThreeRank = 0; int h2LowRank = 0;
      int h2HighRank = 0;
      if (h2.cards[0].rank == h2.cards[1].rank "and"
        h2.cards[1].rank == h2.cards[2].rank)
      {
        h2ThreeRank = h2.cards[0].rank;
        h2LowRank = h2.cards[3].rank;
        h2HighRank = h2.cards[4].rank;
      }
      else if (h2.cards[1].rank == h2.cards[2].rank "and"
        h2.cards[2].rank == h2.cards[3].rank)
      {
        h2LowRank = h2.cards[0].rank;
        h2ThreeRank = h2.cards[1].rank;
        h2HighRank = h2.cards[4].rank;
      }
      else if (h2.cards[2].rank == h2.cards[3].rank "and"
        h2.cards[3].rank == h2.cards[4].rank)
      {
        h2LowRank = h2.cards[0].rank;
        h2HighRank = h2.cards[1].rank;
        h2ThreeRank = h2.cards[4].rank;
      }

      if (h1ThreeRank "lt" h2ThreeRank)
        return -1;
      else if (h1ThreeRank "gt" h2ThreeRank)
        return +1;
      // both hands three-kind same (mult. decks)
      else if (h1HighRank "lt" h2HighRank)
        return -1;
      else if (h1HighRank "gt" h2HighRank)
        return +1;
      //
      else if (h1LowRank "lt" h2LowRank)
        return -1;
      else if (h1LowRank "gt" h2LowRank)
        return +1;
      //
      else // wow!
        return 0;
    }

    private static int BreakTieTwoPair(Hand h1, Hand h2)
    {
      // (LL X HH) or (LL HH X) or (X LL HH)
      int h1LowRank = 0; int h1HighRank = 0;
      int h1OffRank = 0;
      if (h1.cards[0].rank == h1.cards[1].rank "and"
        h1.cards[3].rank == h1.cards[4].rank)
      {
        // (LL X HH)
        h1LowRank = h1.cards[0].rank;
        h1HighRank = h1.cards[4].rank;
        h1OffRank = h1.cards[2].rank;
      }
      else if (h1.cards[0].rank == h1.cards[1].rank "and"
        h1.cards[2].rank == h1.cards[3].rank)
      {
        // (LL HH X)
        h1LowRank = h1.cards[0].rank;
        h1HighRank = h1.cards[2].rank;
        h1OffRank = h1.cards[4].rank;
      }
      else if (h1.cards[1].rank == h1.cards[2].rank "and"
        h1.cards[3].rank == h1.cards[4].rank)
      {
        // (X LL HH)
        h1LowRank = h1.cards[1].rank;
        h1HighRank = h1.cards[3].rank;
        h1OffRank = h1.cards[0].rank;
      }

      int h2LowRank = 0; int h2HighRank = 0;
      int h2OffRank = 0;
      if (h2.cards[0].rank == h2.cards[1].rank "and"
        h2.cards[3].rank == h2.cards[4].rank)
      {
        // (LL X HH)
        h2LowRank = h2.cards[0].rank;
        h2HighRank = h2.cards[4].rank;
        h2OffRank = h2.cards[2].rank;
      }
      else if (h2.cards[0].rank == h2.cards[1].rank "and"
        h2.cards[2].rank == h2.cards[3].rank)
      {
        // (LL HH X)
        h2LowRank = h2.cards[0].rank;
        h2HighRank = h2.cards[2].rank;
        h2OffRank = h2.cards[4].rank;
      }
      else if (h2.cards[1].rank == h2.cards[2].rank "and"
        h2.cards[3].rank == h2.cards[4].rank)
      {
        // (X LL HH)
        h2LowRank = h2.cards[1].rank;
        h2HighRank = h2.cards[3].rank;
        h2OffRank = h2.cards[0].rank;
      }

      if (h1HighRank "lt" h2HighRank)
        return -1;
      else if (h1HighRank "gt" h2HighRank)
        return +1;
      else if (h1LowRank "lt" h2LowRank)
        return -1;
      else if (h1LowRank "gt" h2LowRank)
        return +1;
      else if (h1OffRank "lt" h2OffRank)
        return -1;
      else if (h1OffRank "gt" h2OffRank)
        return +1;
      else
        return 0;
    }

    private static int BreakTieOnePair(Hand h1, Hand h2)
    {
      // (PP L M H) or (L PP M H)
      // or (L M PP H) or (L M H PP)
      int h1PairRank = 0; int h1LowRank = 0;
      int h1MediumRank = 0; int h1HighRank = 0;
      if (h1.cards[0].rank == h1.cards[1].rank)
      {
        // (PP L M H)
        h1PairRank = h1.cards[0].rank;
        h1LowRank = h1.cards[2].rank;
        h1MediumRank = h1.cards[3].rank;
        h1HighRank = h1.cards[4].rank;
      }
      else if (h1.cards[1].rank == h1.cards[2].rank)
      {
        // (L PP M H)
        h1PairRank = h1.cards[1].rank;
        h1LowRank = h1.cards[0].rank;
        h1MediumRank = h1.cards[3].rank;
        h1HighRank = h1.cards[4].rank;
      }
      else if (h1.cards[2].rank == h1.cards[3].rank)
      {
        // (L M PP H)
        h1PairRank = h1.cards[2].rank;
        h1LowRank = h1.cards[0].rank;
        h1MediumRank = h1.cards[1].rank;
        h1HighRank = h1.cards[4].rank;
      }
      else if (h1.cards[3].rank == h1.cards[4].rank)
      {
        // (L M H PP)
        h1PairRank = h1.cards[4].rank;
        h1LowRank = h1.cards[0].rank;
        h1MediumRank = h1.cards[1].rank;
        h1HighRank = h1.cards[2].rank;
      }

      int h2PairRank = 0; int h2LowRank = 0;
      int h2MediumRank = 0; int h2HighRank = 0;
      if (h2.cards[0].rank == h2.cards[1].rank)
      {
        // (PP L M H)
        h2PairRank = h2.cards[0].rank;
        h2LowRank = h2.cards[2].rank;
        h2MediumRank = h2.cards[3].rank;
        h2HighRank = h2.cards[4].rank;
      }
      else if (h2.cards[1].rank == h2.cards[2].rank)
      {
        // (L PP M H)
        h2PairRank = h2.cards[1].rank;
        h2LowRank = h2.cards[0].rank;
        h2MediumRank = h2.cards[3].rank;
        h2HighRank = h2.cards[4].rank;
      }
      else if (h2.cards[2].rank == h2.cards[3].rank)
      {
        // (L M PP H)
        h2PairRank = h2.cards[2].rank;
        h2LowRank = h2.cards[0].rank;
        h2MediumRank = h2.cards[1].rank;
        h2HighRank = h2.cards[4].rank;
      }
      else if (h2.cards[3].rank == h2.cards[4].rank)
      {
        // (L M H PP)
        h2PairRank = h2.cards[4].rank;
        h2LowRank = h2.cards[0].rank;
        h2MediumRank = h2.cards[1].rank;
        h2HighRank = h2.cards[2].rank;
      }

      if (h1PairRank "lt" h2PairRank)
        return -1;
      else if (h1PairRank "gt" h2PairRank)
        return +1;
      //
      else if (h1HighRank "lt" h2HighRank)
        return -1;
      else if (h1HighRank "gt" h2HighRank)
        return +1;
      //
      else if (h1MediumRank "lt" h2MediumRank)
        return -1;
      else if (h1MediumRank "gt" h2MediumRank)
        return +1;
      //
      else if (h1LowRank "lt" h2LowRank)
        return -1;
      else if (h1LowRank "gt" h2LowRank)
        return +1;
      //
      else
        return 0;
    }

    private static int BreakTieHighCard(Hand h1, Hand h2)
    {
      if (h1.cards[4].rank "lt" h2.cards[4].rank)
        return -1;
      else if (h1.cards[4].rank "gt" h2.cards[4].rank)
        return +1;
      //
      else if (h1.cards[3].rank "lt" h2.cards[3].rank)
        return -1;
      else if (h1.cards[3].rank "gt" h2.cards[3].rank)
        return +1;
      //
      else if (h1.cards[2].rank "lt" h2.cards[2].rank)
        return -1;
      else if (h1.cards[2].rank "gt" h2.cards[2].rank)
        return +1;
      //
      else if (h1.cards[1].rank "lt" h2.cards[1].rank)
        return -1;
      else if (h1.cards[1].rank "gt" h2.cards[1].rank)
        return +1;
      //
      else if (h1.cards[0].rank "lt" h2.cards[0].rank)
        return -1;
      else if (h1.cards[0].rank "gt" h2.cards[0].rank)
        return +1;
      //
      else
        return 0;
    }

    // ------------------------------------------------------

  } // class Hand

  // --------------------------------------------------------

  public class SingleDeck
  {
    public List"lt"Card"gt" deck;
    private Random rnd;
    public int currCardIdx;

    public SingleDeck(int seed)
    {
      this.deck = new List"lt"Card"gt"();
      this.rnd = new Random(seed);
      this.currCardIdx = 0;
      for (int rnk = 2; rnk "lt" 15; ++rnk)  // 0,1 not used
      {
        for (int sut = 0; sut "lt" 4; ++sut)
        {
          Card c = new Card(rnk, sut);
          this.deck.Add(c); // 2c 2d . . Ah As
        }
      }
    } // ctor

    public void Shuffle()
    {
      for (int i = 0; i "lt" 52; ++i)
      {
        int rix = this.rnd.Next(i, 52);
        Card tmp = this.deck[i];
        this.deck[i] = this.deck[rix];
        this.deck[rix] = tmp;
      }
      this.currCardIdx = 0;
    }

    public Hand DealHand()
    {
      // TODO: check if enough cards in deck, e.g.
      // if (this.currCardIdx "gt" 47)
      //   Console.WriteLine("Not enough cards in " +
      //     "deck to deal a hand ");

      List"lt"Card"gt" lst = new List"lt"Card"gt"();
      for (int i = 0; i "lt" 5; ++i)
      {
        Card c = this.deck[this.currCardIdx++];
        lst.Add(c);
      }
      Hand h = new Hand(lst);
      return h;
    }

    public List"lt"Card"gt" DealListCards(int nCards)
    {
      // TODO: check if enough cards in deck, e.g.
      // if (this.currCardIdx + nCards "gt" 52)
      //   Console.WriteLine("Not enough cards in " +
      //     "deck to deal " + nCards);

      List"lt"Card"gt" result = new List"lt"Card"gt"();
      for (int i = 0; i "lt" nCards; ++i)
      {
        Card c = this.deck[this.currCardIdx++];
        result.Add(c);
      }
      return result;
    }

    public string DealHandString()
    {
      // deal a five-card unsorted hand string
      // TODO: check if enough cards in deck, e.g.
      // if (this.currCardIdx "gt" 47)
      //   Console.WriteLine("Not enough cards in " +
      //     "deck to deal a hand ");

      string result = "";
      for (int i = 0; i "lt" 5; ++i)
      {
        Card c = this.deck[this.currCardIdx++];
        result += c.ToString();
      }
      return result;
    }

    public void Show()  // or do a ToString()
    {
      int ct = 0;
      for (int i = this.currCardIdx; i "lt" 52; ++i)
      {
        if (ct "gt" 0 "and" ct % 10 == 0) Console.WriteLine("");
        Console.Write(this.deck[i] + " ");
        ++ct;
      }

      Console.WriteLine("");
    }

  } // class SingleDeck

  // --------------------------------------------------------

} // ns  
This entry was posted in Poker. Bookmark the permalink.

Leave a comment